﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using Color = System.Windows.Media.Color;
using Path = System.Windows.Shapes.Path;
using Point = System.Windows.Point;

namespace weBoard
{
    /// <summary>
    /// Inner struct of what we do
    /// </summary>
    public class drawingMachine
    {
        #region Public properties and variables

        public bool CanRaiseUp              //"move" action exec control
        {
            get { return _raiseUp; }
            set { _raiseUp = value; }
        }

        public ContextMenu Menu;            //for selection

        public int GetActionsCount
        {
            get { return _acts.Count; }
        }

        #endregion Public properties and variables

        #region Private properties and variables

        private static Canvas _surface;     //canvas to draw
        private static int _selIdx;         //index of selected object
        private static int _undoRedoIdx;    //index of currently undo-redo action

        private Point _oldPos;              //first position from selection moving start

        private List<weBoardAction> _acts;  //action list

        private double _deltaX;             //for correct mouse-object positioning
        private double _deltaY;             //for correct mouse-object positioning

        private bool _raiseUp;              //see CanRaiseUp

        #endregion Private properties and variables

        #region Public members

        /// <summary>
        /// For correct "undo move"
        /// </summary>
        public void RememberOldPos()
        {
            if (_selIdx >= 0)
                if (_surface.Children[_selIdx] is Rectangle)
                    _oldPos = (Point)((Shape)(_surface.Children[_selIdx])).Tag;
        }

        /// <summary>
        /// Gets last executed action
        /// </summary>
        /// <returns>Last action</returns>
        public weBoardAction GetLastAction()
        {
            if (_acts == null || _acts.Count == 0)
                return null;
            return _acts[_acts.Count - 1];
        }

        /// <summary>
        /// Makes canvas empty and also clears all dependencies
        /// </summary>
        public void Clear()
        {
            ClearDrawings();
            _deltaX = _deltaY = 0.0;
            _raiseUp = false;
            _selIdx = -1;
            _acts.Clear();
            _undoRedoIdx = -1;
        }

        /// <summary>
        /// Sets new action list
        /// </summary>
        /// <param name="actions">Action list</param>
        public void SetActions(List<weBoardAction> actions)
        {
            _selIdx = -1;
            _acts = actions;
            if (null == _acts)
                throw new ArgumentNullException("SetActions::Invalid actions list");
            _undoRedoIdx = _acts.Count - 1;
        }

        /// <summary>
        /// Main constructor
        /// </summary>
        /// <param name="canv">Canvas to bind</param>
        public drawingMachine(Canvas canv)
        {
            SetCanvas(canv);
            SetActions(new List<weBoardAction>());
            _raiseUp = true;
        }

        /// <summary>
        /// Executes action and does all dependent movements
        /// </summary>
        /// <param name="act"></param>
        public void Action(weBoardAction act)
        {
            if (act.Record)
            {
                _acts.Add(act);
                _undoRedoIdx = _acts.Count - 1;
                Debug.WriteLine("Action::" + act.Act + " Object::" + act.Object);
            }
            ExecDependentDraw(act);
        }

        /// <summary>
        /// Prepares "Move" action to be done and calls Action()
        /// </summary>
        /// <param name="pos">Mouse cursor position (relatively to Canvas)</param>
        /// <param name="selColor">Color for selection</param>
        /// <param name="recorded">Record or not</param>
        public void MoveSelectionAction(Point pos, Color selColor, bool recorded)
        {
            if (_selIdx < 0)
                return;
            var sh = (Shape)_surface.Children[_selIdx];
            var act = new weBoardAction
            {
                Act = weActType.Move,
                Now =
                    new weBoardState
                    {
                        Fill = sh.Fill,
                        Height = sh.Height,
                        Width = sh.Width,
                        Text = String.Empty,
                        MetaProperties = null,
                        CoordsA = { X = pos.X + _deltaX, Y = pos.Y + _deltaY }
                    },
                Was =
                    new weBoardState
                    {
                        Fill = sh.Fill,
                        Height = sh.Height,
                        Width = sh.Width,
                        Text = String.Empty,
                        MetaProperties = null
                    }
            };
            if (recorded)
                act.Was.CoordsA = _oldPos;
            else
                if (sh.Tag is Point)
                    act.Was.CoordsA = (Point)sh.Tag;
            act.Object = GetObjectType(_selIdx);
            act.Uid = _surface.Children[_selIdx].Uid;
            act.Record = recorded;
            Action(act);
            sh.Tag = new Point(act.Now.CoordsA.X, act.Now.CoordsA.Y);
            if (_raiseUp)
                (_surface.Children[_selIdx]).MouseLeftButtonUp += OnMouseLeftButtonUp;
            else
                (_surface.Children[_selIdx]).MouseLeftButtonUp -= OnMouseLeftButtonUp;
            Reselect(selColor);
        }

        /// <summary>
        /// Prepares "Recolor" action to be done and calls Action()
        /// </summary>
        /// <param name="objColor">New color for selected object</param>
        /// <param name="recorded">Record or not</param>
        public void RecolorSelectedAction(Color objColor, bool recorded)
        {
            if (_selIdx < 0)
                return;
            var sh = (Shape)_surface.Children[_selIdx];
            var act = new weBoardAction
            {
                Act = weActType.Recolor,
                Now =
                    new weBoardState
                    {
                        Fill = new SolidColorBrush(objColor),
                        Height = sh.Height,
                        Width = sh.Width,
                        Text = String.Empty,
                        MetaProperties = null,
                        CoordsA = { X = ((Point)sh.Tag).X, Y = ((Point)sh.Tag).Y }
                    },
                Was =
                    new weBoardState
                    {
                        Fill = sh.Fill,
                        Height = sh.Height,
                        Width = sh.Width,
                        Text = String.Empty,
                        MetaProperties = null,
                        CoordsA = { X = ((Point)sh.Tag).X, Y = ((Point)sh.Tag).Y }
                    },
                Object = GetObjectType(_selIdx),
                Uid = _surface.Children[_selIdx].Uid,
                Record = recorded
            };
            Action(act);
        }

        /// <summary>
        /// Prepares "Resize" action to be done and calls Action()
        /// </summary>
        /// <param name="newSize">New size of an object</param>
        /// <param name="selColor">Color for selection</param>
        /// <param name="recorded">Record or not</param>
        public void ResizeSelectionAction(double newSize, Color selColor, bool recorded)
        {
            if (_selIdx < 0)
                return;
            var sh = (Shape)_surface.Children[_selIdx];
            var act = new weBoardAction
            {
                Act = weActType.Resize,
                Now =
                    new weBoardState
                    {
                        Fill = sh.Fill,
                        Height = newSize,
                        Width = newSize,
                        Text = String.Empty,
                        MetaProperties = null,
                        CoordsA = { X = ((Point)sh.Tag).X, Y = ((Point)sh.Tag).Y }
                    },
                Was =
                    new weBoardState
                    {
                        Fill = sh.Fill,
                        Height = sh.Height,
                        Width = sh.Width,
                        Text = String.Empty,
                        MetaProperties = null,
                        CoordsA = { X = ((Point)sh.Tag).X, Y = ((Point)sh.Tag).Y }
                    },
                Object = GetObjectType(_selIdx),
                Uid = _surface.Children[_selIdx].Uid,
                Record = recorded
            };
            Action(act);

            Reselect(selColor);
        }

        /// <summary>
        /// Prepares "Delete" action to be done and calls Action()
        /// </summary>
        public void DeleteSelectedAction()
        {
            if (_selIdx < 0)
                return;
            var sh = (Shape)_surface.Children[_selIdx];
            var act = new weBoardAction
            {
                Act = weActType.Delete,
                Now = null,
                Was =
                    new weBoardState
                    {
                        Fill = sh.Fill,
                        Height = sh.Height,
                        Width = sh.Width,
                        Text = String.Empty,
                        MetaProperties = null,
                        CoordsA = { X = ((Point)sh.Tag).X, Y = ((Point)sh.Tag).Y }
                    },
                Object = GetObjectType(_selIdx),
                Uid = _surface.Children[_selIdx].Uid,
                Record = true
            };
            Action(act);
            Deselect();
        }

        /// <summary>
        /// Makes possible to drag objects correctly
        /// </summary>
        /// <param name="pos">Mouse cursor position (relatively to Canvas)</param>
        /// <param name="set">Set or zero deltas</param>
        public void SetDelta(Point pos, bool set)
        {
            if (!set)
            {
                _deltaX = _deltaY = 0.0;
                return;
            }
            if (_selIdx < 0)
                return;
            var sh = (Shape)_surface.Children[_selIdx];
            if (sh is Rectangle)
            {
                _deltaX = ((Point)sh.Tag).X - pos.X;
                _deltaY = ((Point)sh.Tag).Y - pos.Y;
            }
        }

        /// <summary>
        /// Draws select/deselect border
        /// </summary>
        /// <param name="idx">Index of object to select/deselect</param>
        /// <param name="selColor">Color of selection border</param>
        /// <param name="sel">Select or deselect</param>
        public bool Select(int idx, Color selColor, bool sel)
        {
            if (idx < 0 || idx > _surface.Children.Count - 1)
                return false;
            _selIdx = idx;
            var obj = _surface.Children[_selIdx];
            if (!(obj is Shape))
                return false;
            ((Shape)obj).ContextMenu = sel ? Menu : null;
            Panel.SetZIndex(obj, sel ? 999 : 0);
            if (obj is Ellipse)
                SelectEllipse(_selIdx, selColor, sel);
            if (obj is Rectangle)
                SelectRect(_selIdx, selColor, sel);
            if (obj is Line)
                SelectLine(_selIdx, selColor, sel);
            if (obj is Path)
                SelectPath(_selIdx, selColor, sel);
            if (obj is Polyline)
                SelectPolyline(_selIdx, selColor, sel);
            if (obj is Polygon)
                SelectPolygon(_selIdx, selColor, sel);
            return true;
        }

        /// <summary>
        /// Performs deselection and then selects again with the right color
        /// </summary>
        /// <param name="selColor">Actual color for selection</param>
        public void Reselect(Color selColor)
        {
            var tmp = _selIdx;
            Deselect();
            _selIdx = tmp;
            Select(_selIdx, selColor, true);
        }

        /// <summary>
        /// Deselects selected object
        /// </summary>
        public void Deselect()
        {
            Select(_selIdx, Colors.Black, false);
        }

        /// <summary>
        /// Undo implementation
        /// </summary>
        public weBoardAction Undo()
        {
            if (_undoRedoIdx < 0)
                return null;
            if (_undoRedoIdx > _acts.Count - 1)
                _undoRedoIdx = _acts.Count - 1;
            var act = _acts[_undoRedoIdx];
            var antiAct = new weBoardAction
            {
                Act = act.Act,
                Object = act.Object,
                Record = false,
                Uid = act.Uid,
                Now = act.Was
            };
            switch (act.Act)
            {
                case weActType.Create:
                    antiAct.Act = weActType.Delete;
                    antiAct.Now = act.Now;
                    break;
                case weActType.Delete:
                    antiAct.Act = weActType.Create;
                    antiAct.Now = act.Was;
                    break;
            }
            Deselect();
            ExecDependentDraw(antiAct);
            if (_undoRedoIdx >= 0)
                _undoRedoIdx--;
            return antiAct;
        }

        /// <summary>
        /// Redo implementation
        /// </summary>
        public weBoardAction Redo()
        {
            if (_acts.Count == 0)
                return null;
            if (_undoRedoIdx > _acts.Count - 1)
                _undoRedoIdx = _acts.Count - 1;
            if (_undoRedoIdx < _acts.Count - 1)
                _undoRedoIdx++;
            Deselect();
            ExecDependentDraw(_acts[_undoRedoIdx]);
            return _acts[_undoRedoIdx];
        }

        /// <summary>
        /// Converts XML/binary/text data file to actions
        /// </summary>
        /// <param name="filename">File to open</param>
        /// <param name="xml">Opening mode xml or bin</param>
        public void Open(String filename, bool xml)
        {
            Clear();
            if (xml)
                OpenXml(filename);
            else
                OpenBin(filename);
            Play();
        }

        /// <summary>
        /// Saves all actions to file
        /// </summary>
        /// <param name="filename">File to save</param>
        /// <param name="xml">Opening mode xml or bin</param>
        public void Save(String filename, bool xml)
        {
            if (xml)
                SaveXml(filename, _acts.Count - 1);
            else
                SaveBin(filename, _acts.Count - 1);
        }

        /// <summary>
        /// Just draws all
        /// </summary>
        public void Play()
        {
            Play(0, _acts.Count - 1);
        }
        #endregion Public members

        #region Private members

        private static void DeleteObject(Canvas canv, weBoardAction act)
        {
            var idx = GetIndex(canv, act);
            if (idx < 0)
                return;
            canv.Children.RemoveAt(idx);
        }

        private static int GetIndex(Canvas canv, weBoardAction act)
        {
            if (null == act || null == canv)
                return -1;
            foreach (UIElement item in canv.Children)
                if (item.Uid == act.Uid)
                    return canv.Children.IndexOf(item);
            return -1;
        }

        /// <summary>
        /// Binds new canvas to draw on it
        /// </summary>
        /// <param name="canv">Canvas</param>
        private void SetCanvas(Canvas canv)
        {
            _selIdx = -1;
            _surface = canv;
            if (null == _surface)
                throw new ArgumentNullException("SetCanvas::Invalid drawing surface");
        }

        /// <summary>
        /// Makes canvas empty
        /// </summary>
        private void ClearDrawings()
        {
            _selIdx = -1;
            _surface.Children.Clear();
        }

        /// <summary>
        /// Returns type of requested object by it's index
        /// </summary>
        /// <param name="idx">Index to operate with</param>
        /// <returns></returns>
        private weObjType GetObjectType(int idx)
        {
            var shape = (Shape)_surface.Children[idx];
            if (shape is Ellipse)
                return weObjType.ObjEllipse;
            if (shape is Rectangle)
                return weObjType.ObjRect;
            if (shape is Line)
                return weObjType.ObjLine;
            if (shape is Polyline)
                return weObjType.ObjPolyline;
            if (shape is Polygon)
                return weObjType.ObjPolygon;
            if (shape is Path)
                return weObjType.ObjPath;
            throw new ArgumentOutOfRangeException("GetObjectType::Unknown object type");
        }

        /// <summary>
        /// Selects or deselects Polygon
        /// </summary>
        /// <param name="idx">Index of object to select or deselect</param>
        /// <param name="selColor">Selection color</param>
        /// <param name="sel">Select or deselect</param>
        private static void SelectPolygon(int idx, Color selColor, bool sel)
        {
            //TODO
            if (sel)
            {   
            }
            else
            {
                _selIdx = -1;
            }
        }

        /// <summary>
        /// Selects or deselects Polyline
        /// </summary>
        /// <param name="idx">Index of object to select or deselect</param>
        /// <param name="selColor">Selection color</param>
        /// <param name="sel">Select or deselect</param>
        private static void SelectPolyline(int idx, Color selColor, bool sel)
        {
            //TODO
            if (sel)
            {
            }
            else
            {
                _selIdx = -1;
            }
        }

        /// <summary>
        /// Selects or deselects Ellipse
        /// </summary>
        /// <param name="idx">Index of object to select or deselect</param>
        /// <param name="selColor">Selection color</param>
        /// <param name="sel">Select or deselect</param>
        private static void SelectEllipse(int idx, Color selColor, bool sel)
        {
            //TODO
            if (sel)
            {
            }
            else
            {
                _selIdx = -1;
            }
        }

        /// <summary>
        /// Selects or deselects Line
        /// </summary>
        /// <param name="idx">Index of object to select or deselect</param>
        /// <param name="selColor">Selection color</param>
        /// <param name="sel">Select or deselect</param>
        private static void SelectLine(int idx, Color selColor, bool sel)
        {
            //TODO
            if (sel)
            {
            }
            else
            {
                _selIdx = -1;
            }
        }

        /// <summary>
        /// Selects or deselects Path
        /// </summary>
        /// <param name="idx">Index of object to select or deselect</param>
        /// <param name="selColor">Selection color</param>
        /// <param name="sel">Select or deselect</param>
        private static void SelectPath(int idx, Color selColor, bool sel)
        {
            //TODO
            if (sel)
            {
            }
            else
            {
                _selIdx = -1;
            } 
        }

        /// <summary>
        /// Selects or deselects Rect
        /// </summary>
        /// <param name="idx">Index of object to select or deselect</param>
        /// <param name="selColor">Selection color</param>
        /// <param name="sel">Select or deselect</param>
        private static void SelectRect(int idx, Color selColor, bool sel)
        {
            if (idx < 0 || idx > _surface.Children.Count - 1)
                return;
            var rect = (Rectangle)_surface.Children[idx];
            if (rect.Uid.Contains("-sel"))
                return;
            if (sel)
            {
                var selWidth = rect.Width + 4;
                var selHeight = rect.Height + 4;
                var selObj = new Rectangle
                {
                    Width = selWidth,
                    Height = selHeight,
                    Stroke = new SolidColorBrush(selColor),
                    StrokeThickness = 2,
                    Opacity = 1
                };
                var pt = (Point)(rect.Tag);
                Canvas.SetTop(selObj, pt.Y - 2);
                Canvas.SetLeft(selObj, pt.X - 2);
                selObj.Uid = rect.Uid + "-sel";
                selObj.Tag = new Point(pt.X - 2, pt.Y - 2);
                _surface.Children.Add(selObj);
                Panel.SetZIndex(selObj, 999);
            }
            else
            {
                var act = new weBoardAction {Uid = rect.Uid + "-sel", Record = false};
                DeleteObject(_surface, act);
                _selIdx = -1;
            }
        }

        /// <summary>
        /// Raises "move" action after mouseleftbuttonup event above shape object (not Canvas)
        /// </summary>
        private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs mouseButtonEventArgs)
        {
            if (_selIdx >= 0 && _selIdx <= _surface.Children.Count - 1)
            {
                (_surface.Children[_selIdx]).MouseLeftButtonUp -= OnMouseLeftButtonUp;
                _surface.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left)
                {
                    RoutedEvent = Mouse.MouseUpEvent,
                    Source = this,
                });
                mouseButtonEventArgs.Handled = true;
            }   
        }

        /// <summary>
        /// Classifies action and retranslates it to specified routines
        /// </summary>
        /// <param name="act">Action to classify</param>
        private void ExecDependentDraw(weBoardAction act)
        {
            switch (act.Object)
            {
                case weObjType.ObjPolygon:  {DrawPolygon(act);  break;}
                case weObjType.ObjPolyline: {DrawPolyline(act); break;}
                case weObjType.ObjEllipse:  {DrawEllipse(act);  break;}
                case weObjType.ObjLine:     {DrawLine(act);     break;}
                case weObjType.ObjPath:     {DrawPath(act);     break;}
                case weObjType.ObjPoint:    {DrawPoint(act);    break;}
                case weObjType.ObjRect:     {DrawRect(act);     break;}
            }
        }

        /// <summary>
        /// Draws Polyline with given conditions
        /// </summary>
        /// <param name="act">What to do</param>
        private static void DrawPolyline(weBoardAction act)
        {
            //TODO
            switch (act.Act)
            {
                case weActType.Create:
                    //create polyline
                    break;
                case weActType.Delete:
                    //delete polyline
                    break;
                case weActType.Move:
                    //move polyline
                    break;
                case weActType.Recolor:
                    //recolor polyline
                    break;
                case weActType.Resize:
                    //resize polyline
                    break;
            }
        }

        /// <summary>
        /// Draws Ellipse with given conditions
        /// </summary>
        /// <param name="act">What to do</param>
        private static void DrawEllipse(weBoardAction act)
        {
            //TODO
            switch (act.Act)
            {
                case weActType.Create:
                    //create ellipse
                    break;
                case weActType.Delete:
                    //delete ellipse
                    break;
                case weActType.Move:
                    //move ellipse
                    break;
                case weActType.Recolor:
                    //recolor ellipse
                    break;
                case weActType.Resize:
                    //resize ellipse
                    break;
            }
        }

        /// <summary>
        /// Draws Line with given conditions
        /// </summary>
        /// <param name="act">What to do</param>
        private static void DrawLine(weBoardAction act)
        {
            var idx = GetIndex(_surface, act);
            switch (act.Act)
            {
                case weActType.Create:
                    var pt = new Line
                    {
                        Uid = act.Uid,
                        HorizontalAlignment = HorizontalAlignment.Center,
                        VerticalAlignment = VerticalAlignment.Center,
                        Stroke = act.Now.Fill,
                        StrokeThickness = act.Now.Width,
                        Tag = new List<Point> {new Point(act.Now.CoordsA.X, act.Now.CoordsA.Y), new Point(act.Now.CoordsB.X, act.Now.CoordsB.Y)},
                        X1 = act.Now.CoordsA.X,
                        Y1 = act.Now.CoordsA.Y,
                        X2 = act.Now.CoordsB.X,
                        Y2 = act.Now.CoordsB.Y,
                    };
                    _surface.Children.Add(pt);
                    break;
                case weActType.Delete:
                    SelectLine(idx, Colors.White, false);
                    DeleteObject(_surface, act);
                    break;
                case weActType.Move:
                    if (idx >= 0)
                    {
                        //Canvas.SetTop(_surface.Children[idx], act.Now.CoordsA.Y);
                        //Canvas.SetLeft(_surface.Children[idx], act.Now.CoordsA.X);
                        //((Shape) _surface.Children[idx]).Tag = new Point(act.Now.CoordsA.X, act.Now.CoordsA.Y);
                    }
                    break;
                case weActType.Recolor:
                    if (idx >= 0)
                    {
                        ((Shape) _surface.Children[idx]).Stroke = act.Now.Fill;
                    }
                    break;
                case weActType.Resize:
                    if (idx >= 0)
                    {
                        ((Shape)_surface.Children[idx]).StrokeThickness = act.Now.Width;
                    }
                    break;
            }

            //TODO
        }

        /// <summary>
        /// Draws Path with given conditions
        /// </summary>
        /// <param name="act">What to do</param>
        private static void DrawPath(weBoardAction act)
        {
            //TODO
            switch (act.Act)
            {
                case weActType.Create:
                    //create path
                    break;
                case weActType.Delete:
                    //delete path
                    break;
                case weActType.Move:
                    //move path
                    break;
                case weActType.Recolor:
                    //recolor path
                    break;
                case weActType.Resize:
                    //resize path
                    break;
            }
        }

        /// <summary>
        /// Draws Point with given conditions
        /// </summary>
        /// <param name="act">What to do</param>
        private static void DrawRect(weBoardAction act)
        {
            var idx = GetIndex(_surface, act);
            switch (act.Act)
            {
                case weActType.Create:
                    var pt = new Rectangle
                    {
                        Uid = act.Uid,
                        Width = act.Now.Width,
                        Height = act.Now.Height,
                        Fill = act.Now.Fill,
                        Tag = new Point(act.Now.CoordsA.X, act.Now.CoordsA.Y)
                    };
                    _surface.Children.Add(pt);
                    Canvas.SetTop(pt, act.Now.CoordsA.Y);
                    Canvas.SetLeft(pt, act.Now.CoordsA.X);
                    break;
                case weActType.Delete:
                    SelectRect(idx, Colors.White, false);
                    DeleteObject(_surface, act);
                    break;
                case weActType.Move:
                    if (idx >= 0)
                    {
                        Canvas.SetTop(_surface.Children[idx], act.Now.CoordsA.Y);
                        Canvas.SetLeft(_surface.Children[idx], act.Now.CoordsA.X);
                        ((Shape) _surface.Children[idx]).Tag = new Point(act.Now.CoordsA.X, act.Now.CoordsA.Y);
                    }
                    break;
                case weActType.Recolor:
                    if (idx >= 0)
                    {
                        ((Shape) _surface.Children[idx]).Fill = act.Now.Fill;
                    }
                    break;
                case weActType.Resize:
                    if (idx >= 0)
                    {
                        ((Shape) _surface.Children[idx]).Width = act.Now.Width;
                        ((Shape) _surface.Children[idx]).Height = act.Now.Height;
                    }
                    break;
            }
        }

        /// <summary>
        /// Draws Rect with given conditions
        /// </summary>
        /// <param name="act">What to do</param>
        private void DrawPoint(weBoardAction act)
        {
            DrawRect(act);//In fact point is a special "Filled rect"
        }

        /// <summary>
        /// Draws polygon with given conditions
        /// </summary>
        /// <param name="act">What to do</param>
        private void DrawPolygon(weBoardAction act)
        {
            //TODO
            switch (act.Act)
            {
                case weActType.Create:
                    //create polygon
                    break;
                case weActType.Delete:
                    //delete polygon
                    break;
                case weActType.Move:
                    //move polygon
                    break;
                case weActType.Recolor:
                    //recolor polygon
                    break;
                case weActType.Resize:
                    //resize polygon
                    break;
            }
        }

        /// <summary>
        /// Opens XML weBoard action list
        /// </summary>
        /// <param name="filename">File to open</param>
        private void OpenXml(String filename)
        {
            var serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<weBoardAction>));
            using (var reader = new StreamReader(filename))
                _acts = (List<weBoardAction>)serializer.Deserialize(reader);
        }

        /// <summary>
        /// Opens binary compressed weBoard action list
        /// </summary>
        /// <param name="filename">File to open</param>
        private void OpenBin(String filename)
        {
            var fInfo = new FileInfo(filename);
            var iStream = new MemoryStream();
            using (var inF = fInfo.OpenRead())
            {
                using (var decompress = new GZipStream(inF, CompressionMode.Decompress))
                {
                    var buffer = new byte[16384];
                    int numRead;
                    while ((numRead = decompress.Read(buffer, 0, buffer.Length)) != 0)
                        iStream.Write(buffer, 0, numRead);
                }
            }
            var serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<weBoardAction>));
            iStream.Seek(0, SeekOrigin.Begin);
            using (var reader = new StreamReader(iStream))
                _acts = (List<weBoardAction>)serializer.Deserialize(reader);
        }

        /// <summary>
        /// Saves XML weBoard action list
        /// </summary>
        /// <param name="filename">File to save</param>
        /// <param name="endIdx">End index</param>
        private void SaveXml(String filename, int endIdx)
        {
            if (endIdx > _acts.Count - 1 || endIdx <= 0)
                return;
            if (!filename.EndsWith(".weboard"))
                filename += ".weboard";
            var recorded = new List<weBoardAction>(_acts);
            recorded.RemoveRange(endIdx, recorded.Count - endIdx - 1);
            var serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<weBoardAction>));
            using (var writer = new StreamWriter(filename))
                serializer.Serialize(writer, recorded);
        }

        /// <summary>
        /// Saves binary compressed weBoard action list
        /// </summary>
        /// <param name="filename">File to save</param>
        /// <param name="endIdx">End index</param>
        private void SaveBin(String filename, int endIdx)
        {
            if (!filename.EndsWith(".weboardz"))
                filename += ".weboardz";
            var tmpFile = filename.Remove(filename.IndexOf(".weboardz", StringComparison.Ordinal)) + ".weboard";
            SaveXml(tmpFile, endIdx);
            var fInfo = new FileInfo(tmpFile);
            using (var inF = fInfo.OpenRead())
            {
                using (var outF = File.Create(filename))
                {
                    using (var compress = new GZipStream(outF, CompressionMode.Compress))
                    {
                        var buffer = new byte[16384];
                        int numRead;
                        while ((numRead = inF.Read(buffer, 0, buffer.Length)) != 0)
                            compress.Write(buffer, 0, numRead);
                    }
                }
            }
            File.Delete(tmpFile);
        }

        /// <summary>
        /// Just draws given part of actions
        /// </summary>
        /// <param name="startIdx">Start index</param>
        /// <param name="endIdx">End index</param>
        private void Play(int startIdx, int endIdx)
        {
            if (startIdx < 0 || startIdx >= _acts.Count - 1)
                return;
            if (endIdx < startIdx)
                return;
            if (endIdx > _acts.Count - 1)
                return;
            for (var idx = startIdx; idx <= endIdx; idx++)
            {
                ExecDependentDraw(_acts[idx]);
            }
        }
        #endregion Private members
    }

}